package com.auxgroup.smarthome.job.peakvalley;

import com.auxgroup.smarthome.app.entity.AppPeakValleyRedisEntity;
import com.auxgroup.smarthome.enterprise.service.AuxAnalysisService;
import com.auxgroup.smarthome.repo.AppPeakValleyRedisRepo;
import com.auxgroup.smarthome.service.AppElectricityStatisticsService;
import com.auxgroup.smarthome.utils.NewDateUtils;
import com.auxgroup.smarthome.utils.common.LOG;
import com.auxgroup.smarthome.web.ApiResponse;
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * Created by kevinchen on 2017/9/14.
 * 每天凌晨0:00 统计 过去一天的波峰波谷波平的总耗电值
 */
@Component
public class AppPeakValleyJob  implements SimpleJob {

    @Autowired
    private AppPeakValleyRedisRepo appPeakValleyRedisRepo;
    @Autowired
    private AuxAnalysisService auxAnalysisService;
    @Autowired
    private AppElectricityStatisticsService electricityStatisticsService;


    /**
     * 保存日用电总量\保存月用电总量\保存年用电总量 这三个事件一定得串行，不能并行。
     * 故在此不能采用异步的事件驱动模式
     *
     * 修改 暂时需求中没有设计到统计每年的用电总量
     * @param shardingContext
     */
    @Override
    public void execute(ShardingContext shardingContext) {
        List<AppPeakValleyRedisEntity> peakValleyRedisEntities = appPeakValleyRedisRepo.getPartDataList(shardingContext.getShardingItem(), AppPeakValleyRedisEntity.class);
        StringBuilder logBuild = new StringBuilder();
        logBuild.append("任务名称：").append(shardingContext.getJobName()).append("--分片No:").append(shardingContext.getShardingItem()).append("--数据长度").append(peakValleyRedisEntities.size());
        LOG.info(this,logBuild.toString());
        peakValleyRedisEntities.stream().forEach(peakValleyRedisEntity->{
            //保存日用电总量
            Pair<Float, Float> dayPeakValleyInfo = getEveryDayPeakValleyInfo(peakValleyRedisEntity);
            String pk = peakValleyRedisEntity.getPk();
            String did = peakValleyRedisEntity.getDid();
            Float left = dayPeakValleyInfo.getLeft();
            Float right = dayPeakValleyInfo.getRight();
            String timeBucket = peakValleyRedisEntity.getTimeBucket();
            electricityStatisticsService.saveDayElectricStaticsResult(pk,did, left, right,peakValleyRedisEntity.getTimeBucket());
            //保存月用电总量
            electricityStatisticsService.addMothElectricStatisticsResult(pk,did, left, right);
            //保存年用电总量
            electricityStatisticsService.addYearElectricStatisticsResult(pk,did, left, right);
            //删除4个月前过期数据
            electricityStatisticsService.deleteByDidAndTimeStr(did);
            LOG.info(this,"统计 pk = "+pk+", did = "+did+" 的设备在"+timeBucket+
                    "的时间段里的波峰波谷前日用电总量为：波峰="+left+"，波谷="+right);
        });
    }

    /**
     * 同时返回 波峰、波谷、波平三个数值
     * @param peakValleyRedisEntity
     * @return left:波峰用电总量 middle：波谷用电总量  right: 波平用电总量
     */
    private Pair<Float,Float> getEveryDayPeakValleyInfo(AppPeakValleyRedisEntity peakValleyRedisEntity){
        Float peakValue = getPeakValleyValue(peakValleyRedisEntity, 0);
        Float valleyValue = getPeakValleyValue(peakValleyRedisEntity, 1);
        return Pair.of(peakValue,valleyValue);
    }

    /**
     *  求波峰、波谷用电总量
     * @param peakValleyRedisEntity
     * @param type 0 : 求波峰用电总量  1:求波谷用电总量
     * @return
     */
    private Float getPeakValleyValue(AppPeakValleyRedisEntity peakValleyRedisEntity,int type){
        return type==0 ? getPeakTotalValue(peakValleyRedisEntity) : getValleyTotalValue(peakValleyRedisEntity);
    }


    /**
     * 通过平台接口查询 某时间段 波峰用电总量
     * @param peakValleyRedisEntity
     * @return
     */
    private Float getPeakTotalValue(AppPeakValleyRedisEntity peakValleyRedisEntity){
        int peakStartHour = peakValleyRedisEntity.getPeakStartHour();
        int peakEndHour = peakValleyRedisEntity.getPeakEndHour();
        String pk = peakValleyRedisEntity.getPk();
        String did = peakValleyRedisEntity.getDid();
        return getPvtotalValue(pk,did,peakStartHour,peakEndHour);
    }

    /**
     * 通过平台接口查询某时间段波谷用电总量
     * @param peakValleyRedisEntity
     * @return
     */
    private Float getValleyTotalValue(AppPeakValleyRedisEntity peakValleyRedisEntity){
        int valleyStartHour = peakValleyRedisEntity.getValleyStartHour();
        int valleyEndHour = peakValleyRedisEntity.getValleyEndHour();
        String pk = peakValleyRedisEntity.getPk();
        String did = peakValleyRedisEntity.getDid();
        return getPvtotalValue(pk,did,valleyStartHour,valleyEndHour);
    }

    /**
     * 重新封装 auxAnalysisService的获取波峰波谷的调用平台接口的方法
     * 主要是对异常的处理
     * @param pk
     * @param did
     * @param start
     * @param end
     * @return
     */
    private Float getPeakValleyTotalElectric(String pk,String did,String start,String end){
        ApiResponse<Float> apiResponse = auxAnalysisService.getPeakValleyTotalElectric(pk, did, start, end);
        if(!apiResponse.isNotErrorCode()){
            String errmsg = "AppPeakValleyDayJob error : code = "
                    + apiResponse.getCode() + ",msg=" + apiResponse.getMessage();
            LOG.error(this,errmsg);
            throw new IllegalArgumentException("峰谷节点用电统计的时候报错啦："+errmsg);
        }
        Float value = apiResponse.getData();
        return value!=null ? value : 0f;
    }

    /**
     * 提取波峰波谷用电总量计算的通用逻辑
     * @param pk
     * @param did
     * @param startHour
     * @param endHour
     * @return
     */
    private Float getPvtotalValue(String pk,String did,int startHour,int endHour){
        // 未开启峰谷节电的话则是波平
        boolean isDisablePeakOrValley = startHour == endHour || (startHour == 0 && endHour ==0);
        if(isDisablePeakOrValley) {
            return 0F;
        }
        if (endHour != 0 && startHour > endHour){
            String start1 = NewDateUtils.getYesterdayZeroStr();
            String end1 = NewDateUtils.getYesterdayAddHourStr(endHour);
            Float total1 = getPeakValleyTotalElectric(pk, did, start1, end1);
            String start2 = NewDateUtils.getYesterdayAddHourStr(startHour);
            String end2 = NewDateUtils.getTodayZeroStr();
            Float total2 = getPeakValleyTotalElectric(pk, did, start2, end2);
            return total1 + total2;
        }else{
            String start1 = NewDateUtils.getYesterdayAddHourStr(startHour);
            String end1 = endHour == 0 ? NewDateUtils.getTodayZeroStr() : NewDateUtils.getYesterdayAddHourStr(endHour);
            return getPeakValleyTotalElectric(pk, did, start1, end1);
        }
    }

    /**
     *  未开启峰谷节电的情况下，波峰以及波谷都默认为0
     *  当波峰开始和结束时间都为0的时候，认为没有开启
     *  当波谷开始和结束时间都为0的时候，认为没有开启
     * @param peakValleyRedisEntity
     * @param type
     * @return
     */
    @Deprecated
    private boolean isClosePeakValley(AppPeakValleyRedisEntity peakValleyRedisEntity, int type) {
        // 是否关闭波峰
        boolean isClosePeak = type==0 && (peakValleyRedisEntity.getPeakStartHour() == 0 && peakValleyRedisEntity.getPeakEndHour() ==0);
        // 是否关闭波谷
        boolean isCloseVall = type==1 && (peakValleyRedisEntity.getValleyStartHour() == 0 && peakValleyRedisEntity.getValleyStartHour() ==0);
        if(isClosePeak || isCloseVall) {
            return true;
        }
        return false;
    }

    /**
     * 每天用电总量计算
     * @param peakValleyRedisEntity
     * @return
     */
    @Deprecated
    private Float getTotalElectricValue(AppPeakValleyRedisEntity peakValleyRedisEntity){
        ApiResponse<Float> apiResponse = auxAnalysisService.getTotalElectric(peakValleyRedisEntity.getPk(), peakValleyRedisEntity.getDid(), NewDateUtils.getYesterdayStr());
        if(!apiResponse.isNotErrorCode()){
            String errmsg = "AppPeakValleyDayJob error 当天用电总量计算错误 : code = "
                    + apiResponse.getCode() + ",msg=" + apiResponse.getMessage();
            LOG.error(this,errmsg);
            throw new IllegalArgumentException(errmsg);
        }
        Float value = apiResponse.getData();
        return value!=null ? value :0f;
    }



}
